<template>
  <div class="employees-container">
    <div class="app-container">
      <!-- 通用工具栏组件使用 -->
      <page-tools>
        <!-- 自定义左侧内容 -->
        <template #slot-left>
          <span>共19条记录</span>
        </template>

        <!-- 自定义右侧内容 -->
        <template #slot-right>
          <!-- impor和export要和权限点标识英文必须一致才能使用
          而且还要给员工分配上才能看到 -->
          <el-button v-power="'import'" type="danger" size="small" @click="uploadExcelBtnFn">导入excel</el-button>
          <el-button v-power="'export'" type="success" size="small" @click="downloadExcel">导出excel</el-button>
          <el-button type="primary" size="small" @click="addEmployeesFn">新增员工</el-button>
        </template>
      </page-tools>

      <!-- 表格+分页 -->
      <el-card style="margin-top: 10px;">
        <el-table border :data="employeesList" :default-sort="abc">
          <el-table-column label="序号" type="index" />
          <el-table-column label="姓名" prop="username" />
          <el-table-column label="头像" prop="staffPhoto">
            <template v-slot="scope">
              <image-holder :src="scope.row.staffPhoto" />
            </template>
          </el-table-column>
          <el-table-column label="手机号" prop="mobile" />
          <el-table-column label="工号" prop="workNumber" sortable :sort-method="sortMethodFn" />
          <el-table-column label="聘用形式" prop="formOfEmployment">
            <template v-slot="scope">
              <!-- scope.row.formOfEmployment ? '正式' : '非正式'
                ?左边是1/2 或者字符串'1', '2' 都是true, 原地值始终是'正式' 与我们要的效果不符合
                但是
                scope.row.formOfEmployment === 1 ? '正式' : '非正式'
                ?左边是一个判断===的条件, 整体判断结果在原地作为三元运算符判断条件
                1===1  true  2===1 false (现在效果对的)
               -->
              <!-- <span>{{ scope.row.formOfEmployment === 1 ? '正式' : '非正式' }}</span> -->
              <span>{{ formatFormOfEmploymentFn(scope.row.formOfEmployment) }}</span>
            </template>
          </el-table-column>
          <el-table-column label="聘用形式" prop="formOfEmployment" :formatter="formatFormFn" />
          <el-table-column label="部门" prop="departmentName" />
          <el-table-column label="入职时间" prop="timeOfEntry" />
          <el-table-column label="操作" width="280">
            <template v-slot="scope">
              <el-button type="text" size="small" @click="$router.push(`/employees/detail?id=${scope.row.id}`)">查看</el-button>
              <!-- 员工的ID -->
              <el-button type="text" size="small" @click="addRoleBtnFn(scope.row.id)">分配角色</el-button>
              <el-button type="text" size="small">删除</el-button>
            </template>
          </el-table-column>
        </el-table>
        <!-- 分页组件 -->
        <el-row type="flex" justify="center" align="middle" style="height: 60px">
          <!-- 分页区域 -->
          <el-pagination
            :current-page="query.page"
            :page-sizes="[10, 15, 20, 25]"
            :page-size="query.size"
            layout="total, sizes, prev, pager, next, jumper"
            :total="total"
            @size-change="handleSizeChange"
            @current-change="handleCurrentChange"
          />
        </el-row>
      </el-card>

      <!-- 新增员工-弹窗+表单 -->
      <el-dialog
        title="新增员工"
        :visible.sync="showDialog"
        @close="closeDialogFn"
      >
        <emp-form
          ref="empForm"
          :show-dialog.sync="showDialog"
          :depart-list="departList"
          @enterEV="addFn"
        />
      </el-dialog>

      <!-- 分配角色-弹窗+行列和复选框 -->
      <el-dialog :visible.sync="showAssignRoleDialog">
        <assign-role-dialog
          :role-list="roleList"
          :role-ids="roleIds"
          @close="closeFn"
          @confirmEV="addRoleConfirmFn"
        />
      </el-dialog>
    </div>
  </div>
</template>

<script>
import { getEmployeeListAPI, departmentsListAPI, addEmployeeAPI, getRolesAPI, getUserDetailByIdAPI, assignRolesAPI } from '@/api'
// 树形结构的转换方法
import { transTree } from '@/utils'
import Employees from '@/api/constant/employees.js'
import EmpForm from './component/empForm.vue'
import AssignRoleDialog from './component/assignRoleDialog.vue'
export default {
  name: 'Employees',
  components: {
    EmpForm,
    AssignRoleDialog
  },
  data() {
    return {
      query: {
        page: 1, // 页码
        size: 10 // 每页条数
      },
      employeesList: [], // 员工列表
      departList: [], // 部门列表
      total: 0, // 数据总条数
      showDialog: false, // 新增员工-弹窗显示/隐藏
      abc: {
        prop: 'workNumber'
      },
      showAssignRoleDialog: false, // 分配角色-弹窗显示/隐藏
      roleList: [], // 角色列表
      roleIds: [], // 现有-角色列表
      userId: '' // 查看/分配->角色的员工ID
    }
  },
  created() {
    // 获取员工列表数据
    // 因为一会儿做分页, 我们还得发送请求, 直接调用getEmployeesListFn()
    // 注意: 生命周期方法, 没有挂载到this组件对象身上, this.created()是错误的
    this.getEmployeesListFn()
    // 获取部门列表数据
    this.getDepartmentsListFn()
    // 获取角色列表数据
    this.getRoleListFn()
  },
  methods: {
    // 请求-角色列表数据
    async getRoleListFn() {
      // 默认是获取了第一页10条, 但是后台应该默认返回所有(然后指定页面和页码才应该返回段数, 所以这个问题是后台的, 但是我们只能先传1000解决这个问题)
      const res = await getRolesAPI({
        page: 1,
        pagesize: 1000
      })
      console.log(res)
      this.roleList = res.data.rows
    },
    // 请求-员工列表数据
    async getEmployeesListFn() {
      const res = await getEmployeeListAPI(this.query)
      console.log(res)
      this.employeesList = res.data.rows
      this.total = res.data.total
      // 如何把所有的数据都参与到排序?
      // 思路1: 让后台写. 你需要给后台发送排序的字段(升序还是降序, 要哪一页多少条), 后台有所有数据, 把所有数据进行排序, 你要第几页多少条, 返回第几段往后的条数的数据
      // 思路2: 前端写, 你需要pageSize改很大, 把所有数据请求回来(前提)
      // 分页分段, 排序, 都自己在此函数中拿到数据后, 自己排序, 根据页码和条数, 自己分段取值返回给el-table
      // 数组截取的方法slice()
    },
    // 请求-部门列表数据
    async getDepartmentsListFn() {
      const res = await departmentsListAPI()
      this.departList = transTree(res.data.depts, '') // 指定一级部门的pid值
    },
    // 获取-某个员工的现有的角色列表
    async getUserRoles() {
      const infoRes = await getUserDetailByIdAPI(this.userId)
      if (!infoRes.success) return this.$message.error(infoRes.message)
      this.roleIds = infoRes.data.roleIds || []
      // 如果后台发现roleIds没有就返回null, 导致assignRoleDialog的watch里...null报错
      // 所以我们要是没有值给个空数组, ...[]是不会报错的
    },
    // 每页显示的条数发生改变时触发
    handleSizeChange(newSize) {
      this.query.size = newSize
      this.getEmployeesListFn()
    },
    // 当前页面发生改变时触发
    handleCurrentChange(newPage) {
      this.query.page = newPage
      this.getEmployeesListFn()
    },
    // 格式化聘用形式的数字转文字
    formatFormOfEmploymentFn(num) {
      const obj = {
        1: '正式',
        2: '非正式'
        // 将来有3, 4 , 5就按照这种对应的格式来写
      }
      // 知识点: 对象.具体的key名  (key必须已经在对应里了, obj.1 obj.2)
      // 对象[变量]
      return obj[num]
    },
    // 格式化聘用形式的数字转文字方式2
    formatFormFn(row) {
      // console.log(row.formOfEmployment)
      // 因为id是数字, 但是后台返回的是数字字符串
      const obj = Employees.hireType.find(item => Number(item.id) === Number(row.formOfEmployment))
      return obj ? obj.value : '未知'
    },
    // 自己实现-工号列的排序
    sortMethodFn(a, b) {
      // a和b是数组里相邻的2个值(数据对象)
      // 这里和数组的sort方法使用一致
      // https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
      return a.workNumber - b.workNumber // 字符串相减,会自动转换成数字, 返回数字
    },
    // 新增员工-"按钮"-点击事件
    addEmployeesFn() {
      this.showDialog = true
    },
    // 新增员工-> 子传父事件方法
    async addFn(data) {
      // 把前端新增的数据->后台
      await addEmployeeAPI(data)
      // 从后台再拿到所有数据更新到页面上
      this.getEmployeesListFn()
    },
    // 弹窗-关闭的事件方法
    closeDialogFn() {
      // 关闭弹窗是组件内传值给:visible.sync方式右侧得变量然后流回到组件内, 隐藏标签
      // 重置表单
      // this.$refs.empForm相当于在empForm里this
      this.$refs.empForm.$refs.addForm.resetFields()
    },
    // 导入表格-按钮->点击事件
    uploadExcelBtnFn() {
      // 跳转二级路由到专门上传表格的页面
      this.$router.push('/excel')
    },
    // 导出表格-按钮->点击事件
    downloadExcel() {
      // 相当于 import { excel } from '@/vendor/Export2Excel'
      // 目标: 模块内是export按需导出的, 现在导入如何变成一个大对象
      // import * as 变量名 from '模块'
      // 变量名是一个对象, key就是按需导出的变量名

      // 为何它用函数:
      // 此外，还有一个类似函数的动态 import()，它不需要依赖 type="module" 的script标签。
      // 这里用方法导入的是一个对象里有按需导出的方法

      // 转换数据开始
      // 重要: 页面el-table数据怎么铺设, 和导出的表格之间没有决定性关系
      // 导出表格的数据, 是我们自己用js代码定义的
      // 1. header要的和页面上显示的一样, 都要中文的列标题
      // 操作列是按钮不是数据就不要了
      const headerArr = ['序号', '姓名', '头像', '手机号', '工号', '聘用形式', '部门', '入职时间'] // 8
      // 2. 对象里所有值->转成数组
      // 下面了解-会导致数据对应不上
      // Object.keys() -> 把传入的对象上所有key收集成一个数组 ['id', 'mobile']
      // Object.values() -> 把传入的对象上所有value收集成一个数组 ['001', '123456']
      // 上面2个方法弊端: 对象是无序的, 所以获取的值也是无序的
      // map会收集return的值, 再形成外层的大数组
      // 循环完毕应该是这样[ ['001', '123456'], ['002', '1123'], ['12', '3213'] ]
      // const valueArr = this.employeesList.map(item => {
      //   return Object.values(item)
      // })
      // console.log(valueArr)

      // 2. 正解
      // 2.0 定义对照对象, 中文: 英文key
      const keyObj = {
        '序号': 'id',
        '姓名': 'username',
        '头像': 'staffPhoto',
        '手机号': 'mobile',
        '工号': 'workNumber',
        '聘用形式': 'formOfEmployment',
        '部门': 'departmentName',
        '入职时间': 'timeOfEntry'
      }
      // 2.1 遍历headerArr数组, 拿出中文, 换出英文key
      const valueArr = this.employeesList.map((obj, index) => {
        // 遍历每个数据对象, 用中文key, 去数据对象里找到值, 形成数组
        const newArr = []
        headerArr.forEach(zhKey => {
          const enKey = keyObj[zhKey] // 拿到英文key
          if (enKey === 'id') {
            newArr.push(index + 1)
          } else if (enKey === 'formOfEmployment') { // 聘用形式
            const data = Employees.hireType.find(item => Number(item.id) === Number(obj[enKey]))
            newArr.push(data ? data.value : '未知')
          } else {
            const value = obj[enKey] // 取值
            newArr.push(value)
          }
        })
        return newArr
      })
      // 2.2 再到数据对象里取出对应的值 - 数组遍历是有顺序的
      // 2.3 拿到值放入一个数组里
      // 2.4 2层循环

      // 问题: 为何每次只能导出当前这一页的数据呢?
      // 答案: employeesList数组里只拿到了当前这一页的数据
      // 解决: 目的:拿到所有数据
      // (1): 我不传递任何参数, 和后台约定, 返回所有数据/换一个拿到所有数据的接口 -> 常用
      // (2): 递归(每次请求下一页, 直到没有数据为止, 拼接在一起)

      import('@/vendor/Export2Excel').then(excel => {
        // excel表示导入的模块对象
        excel.export_json_to_excel({
          header: headerArr, // 表头 必填
          data: valueArr, // 具体数据 必填
          // 问题: 点击浏览器卡死, 因为我们的数据格式不对
          filename: '人资员工', // 文件名称
          autoWidth: true, // 宽度是否自适应
          bookType: 'xlsx' // 生成的文件类型
        })
      })
    },
    // 分配角色->按钮点击事件(为了让弹窗出现)
    addRoleBtnFn(employeesId) {
      this.userId = employeesId
      // 获取点击的这个人已有的角色列表
      this.getUserRoles()
      this.showAssignRoleDialog = true
    },
    // 分配角色->确定和取消点击关闭弹窗
    closeFn() {
      this.showAssignRoleDialog = false
    },
    // 分配角色->确定->调用接口发送
    async addRoleConfirmFn(roleIds) {
      const res = await assignRolesAPI({ id: this.userId, roleIds: roleIds })
      if (!res.success) return this.$message.error(res.message)

      // 员工分配成功，给用户提示
      this.$message.success(res.message)
      // 关闭弹框
      this.showRoleDialog = false
      // 重新获取当前当前列表数据
      this.getEmployeeList()
    }
  }
}
</script>

<style lang="scss" scoped></style>
